#include <vector>
#include <iostream>
#include <iterator>
class Vec4
{
public:
    Vec4():_vec(4, 0){}
    class Range{};
    float& operator[](int i){
        if ( i < 0 || i >= 4) throw Range();
        return _vec[i];
    }
    Vec4& operator+=( const Vec4& vec4){
        for(int i = 0; i < 4; ++i)
            _vec[i] += vec4._vec[i];
        return *this;
    }
    Vec4& operator-=( const Vec4& vec4){
        for(int i = 0; i < 4; ++i)
            _vec[i] -= vec4._vec[i];
        return *this;
    }
    Vec4& operator*=( const Vec4& vec4){
        for(int i = 0; i < 4; ++i)
            _vec[i] *= vec4._vec[i];
        return *this;
    }
    Vec4& operator/=( const Vec4& vec4){
        for(int i = 0; i < 4; ++i)
            _vec[i] /= vec4._vec[i];
        return *this;
    }
            
private:
    friend std::ostream& operator<< (std::ostream& , const Vec4& );    
    std::vector<float> _vec;
    
};
std::ostream& operator<< (std::ostream& ios, const Vec4& vec4)
{
    ios << "( ";
    std::copy(vec4._vec.begin(), vec4._vec.end(),
              std::ostream_iterator<float>(ios, ", "));
    ios << " )";
    return ios;
}
Vec4 operator+(const Vec4& left, const Vec4& right)
{
    Vec4 ret = left;
    ret += right;
    return ret;
}
Vec4 operator-(const Vec4& left, const Vec4& right)
{
    Vec4 ret = left;
    ret -= right;
    return ret;
}
Vec4 operator*(const Vec4& left, const Vec4& right)
{
    Vec4 ret = left;
    ret *= right;
    return ret;
}
Vec4 operator/(const Vec4& left, const Vec4& right)
{
    Vec4 ret = left;
    ret /= right;
    return ret;
}
class Mat4
{
public:
    Mat4(const Vec4& v1,const Vec4&v2, const Vec4& v3, const Vec4& v4){
        _m[0] = v1;
        _m[1] = v2;
        _m[2] = v3;
        _m[3] = v4;
    }
    Vec4& operator[]( int index){
        return _m[index];
    }
    friend std::ostream& operator<< (std::ostream& os, const Mat4& mat);
private:
    Vec4 _m[4];
};
std::ostream& operator<< (std::ostream& os, const Mat4& mat)
{
    for(int i = 0; i < 4; i++){
        os << mat._m[i] << std::endl;
    }
    return os;
}

    

    
int main()
{
    try{    
        Vec4 v1,v2;
        
        v1[0] = 1;
        v1[1] = 2;
        v1[2] = 3;
        v1[3] = 4;

        v2[0] = 1;
        v2[1] = 4;
        v2[2] = 3;
        v2[3] = 8;
    
        std::cout << "V1 = " << v1 << std::endl;
        std::cout << "V2 = " << v2 << std::endl;
        std::cout << "V1 + V2 = " << v1+v2 << std::endl;
        std::cout << "V1 - V2 = " << v1-v2 << std::endl;
        std::cout << "V1 * V2 = " << v1*v2 << std::endl;
        std::cout << "V1 / V2 = " << v1/v2 << std::endl;

        Mat4 m(v1+v2, v1-v2, v1*v2, v1/v2);
        std::cout << m << std::endl;

        std::cout << "Operator []" << std::endl;
        std::cout << m[0] << std::endl;
        std::cout << m[1] << std::endl;
        std::cout << m[2] << std::endl;
        std::cout << m[3] << std::endl;
        
        v1[10] = 200;
    }
    catch(Vec4::Range& r){
        std::cout << "Out of Range!" << std::endl;
    }
    
}

    
        
        
